package blockchain.net;

import blockchain.block.Block;
import blockchain.block.MerkleTreeBlockMy;
import blockchain.json.BlockChainJson;
import blockchain.mystream.MyServerSocketNoExcept;
import blockchain.mystream.MySocketNoExcept;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
class MyBlock{
    public static final MerkleTreeBlockMy blockchain = new MerkleTreeBlockMy();
    public static Block get(int i) {
        return blockchain.get(i);
    }
    public static void add(String blockData) {
        blockchain.addBlock(blockData);
    }
    public static int size() {
        return blockchain.size();
    }
    //交换区块
    public static void exchangeBlock(MySocketNoExcept socket) {
        ArrayList<String> arrBlock = new ArrayList<>();
        socket.writeInt(MyBlock.size());
        int size = socket.readInt();
        if (size == MyBlock.size()) {
            return;
        }
        if (size > MyBlock.size()) {
            for (int i = MyBlock.size(); i < size; i++) {
                String blockData = socket.read();
                MyBlock.add(blockData);
            }
        }
        else {
            for (int i = size; i < MyBlock.size(); i++) {
                socket.write(MyBlock.get(i).getData());
            }
        }
    }
    //验证区块
    public static void verifyBlock() {
        ArrayList<Integer> allPortIp = new NetPortScanner().Run();
        for (int ip : allPortIp) {
            String serverIp = BlockChainConfig.subnet + ip;
            MySocketNoExcept socket = new MySocketNoExcept(serverIp, BlockChainConfig.port);
            socket.write(BlockChainConfig.verifyStr);
        }
    }
}

class ServerRunHandler extends Thread{
    private final MySocketNoExcept socket;
    public ServerRunHandler(MySocketNoExcept socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        //接收区块链哈希值验证
        int len = socket.readInt();
        boolean bool = true;
        for (int i = 0; i < len; i++) {
            String readHash = socket.read();
            boolean eql = readHash.equals(MyBlock.get(i).getHash());
            bool &= eql;
        }
        //若验证失败
        if (!bool) {
            socket.writeInt(0);
            //进入查询计数状态
            MyBlock.verifyBlock();
            socket.close();
            return;
        }
        socket.writeInt(1);
        //验证通过，交换区块数据
        MyBlock.exchangeBlock(socket);
        socket.close();
    }
}

class ServerVerifyHandler extends Thread {
    private final MySocketNoExcept socket;
    public ServerVerifyHandler(MySocketNoExcept socket) {
        this.socket = socket;
    }
    @Override
    public void run() {

    }
}

class ServerRun extends Thread{
    private final MyServerSocketNoExcept serverSocket = new MyServerSocketNoExcept(BlockChainConfig.port);
    @Override
    public void run() {
        while (true){
            MySocketNoExcept socket = serverSocket.accept();
            String readData = socket.read();
            if (BlockChainConfig.handStr.equals(readData)) {
                new ServerRunHandler(socket).start();
                continue;
            }
            if (BlockChainConfig.verifyStr.equals(readData)) {
                new ServerVerifyHandler(socket).start();
                continue;
            }
            socket.write("握手不对");
            socket.close();
        }
    }
}

class ClientRun extends Thread {
    @Override
    public void run() {
        ArrayList<Integer> allPortIp = new NetPortScanner().Run();
        for (int ip : allPortIp) {
            String serverIp = BlockChainConfig.subnet + ip;
            MySocketNoExcept socket = new MySocketNoExcept(serverIp, BlockChainConfig.port);
            socket.write(BlockChainConfig.handStr);
            String readData = socket.read();
            if (!BlockChainConfig.handStr.equals(readData)) {
                System.out.println("连接失败");
                socket.close();
                continue;
            }
            //发送区块链哈希值验证
            socket.writeInt(MyBlock.size());
            for (int i = 0; i < MyBlock.size(); i++) {
                socket.write(MyBlock.get(i).getHash());
            }
            //接收验证码，0为不通过
            int bool = socket.readInt();
            if (bool != 1) {
                //进入查询计数状态
                MyBlock.verifyBlock();
                socket.close();
                return;
            }
            //验证通过，交换区块数据
            MyBlock.exchangeBlock(socket);
            socket.close();
        }
    }
}
@Slf4j
public class NetServerScanner {
    public static String serverRun() {
        new ServerRun().start();
        return "原神！启动！";
    }
    public static void clientRun() {
        new ClientRun().start();
    }
//    public static Block get(int id) {
//        return MyBlock.get(id);
//    }
//    public static String getDataString(int id){
//        return MyBlock.get(id).getData();
//    }
    public static void add(BlockChainJson data) {
        String str = data.toJsonString();
        MyBlock.add(str);
    }
    public static ArrayList<BlockChainJson> getAll() {
        ArrayList<BlockChainJson> allBlockChainJson = new ArrayList<>();
        for (int i = 1; i < MyBlock.size(); i++) {
            String data = MyBlock.get(i).getData();
            BlockChainJson blockChainJson = new BlockChainJson(data);
            allBlockChainJson.add(blockChainJson);
        }
//        for (Block block : MyBlock.blockchain.leafValues) {
//            allBlockChainJson.add(new BlockChainJson(block.getData()));
//        }
        //return MyBlock.blockchain.leafValues;
        return allBlockChainJson;
    }
    public static int size() {
        return MyBlock.size();
    }

    public static String defaultBlock() {
        BlockChainJson blockChainJson = new BlockChainJson();
        blockChainJson.batchNumber = "B2025229";
        blockChainJson.temperature = "28.8℃";
        blockChainJson.humidity = "70%";
        blockChainJson.personInCharge = "操作员A";
        blockChainJson.productID = "AGRI-20250493";
        blockChainJson.productionLocation = "山东生产基地";
        blockChainJson.qualityInspector = "质检员B";
        blockChainJson.operatingTime = "2025-01-03";
        NetServerScanner.add(blockChainJson);
        BlockChainJson blockChainJson2 = new BlockChainJson();
        blockChainJson2.qualityInspector = "质检员K";
        blockChainJson2.productionLocation = "福建生产基地";
        blockChainJson2.operatingTime = "2025-02-09";
        blockChainJson2.productID = "AGRI-20250484";
        blockChainJson2.personInCharge = "操作员J";
        blockChainJson2.temperature = "19℃";
        blockChainJson2.humidity = "87%";
        blockChainJson2.batchNumber = "B2025719";
        NetServerScanner.add(blockChainJson2);
        //NetServerScanner.add(new BlockChainJson());
        //NetServerScanner.add(new BlockChainJson());
        BlockChainJson blockChainJson3 = new BlockChainJson();
        blockChainJson3.personInCharge = "操作员E";
        blockChainJson3.productID = "AGRI-20250480";
        blockChainJson3.operatingTime = "2025-02-03";
        blockChainJson3.batchNumber = "B2025404";
        blockChainJson3.qualityInspector = "质检员F";
        blockChainJson3.productionLocation = "浙江生产基地";
        blockChainJson3.humidity = "50%";
        blockChainJson3.temperature = "26℃";
        NetServerScanner.add(blockChainJson3);
        return "区块预设值添加成功";
    }

    public static void main(String[] args) {
        NetServerScanner.defaultBlock();
        ArrayList<BlockChainJson> array = NetServerScanner.getAll();
        for (int i = 0; i < array.size(); i++) {
            BlockChainJson blockChainJson = array.get(i);
            System.out.println(blockChainJson.getHash());
        }
    }
}
